package hotagent;

import java.io.File;
import java.io.IOException;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import utils.CompilerUtil;
import utils.FileUtil;
/**
 * 文件编译重载线程
 * @author jinmiao
 * 2014-8-4 上午11:42:21
 */
public class CheckThread extends Thread
{
	private static final Logger log = Logger.getLogger(CheckThread.class);
	private Instrumentation inst;
	/**
	 * 文件目录 
	 */
	private Map<String, Long> fileMap = new HashMap<String, Long>();
	
	/**
	 * class重载后记录的最后修改时间
	 */
	private Map<String, Long> classMap = new HashMap<String, Long>();
	
	
	public CheckThread(Instrumentation inst)
	{
		this.inst = inst;
	}
	
	@Override
	public void run() {
		
		File file = new File("reload");
		if(file.exists())
		{
			FileUtil.delete(file);
		}
		file.mkdir();
		for(;;)
		{
			try {
				Thread.sleep(1000);
				if(inst==null)
				{
					log.error("重载启动参数未配置!");
					break;
				}
				if(!inst.isRedefineClassesSupported())
				{
					log.error("重载没起开!");
					break;
				}
				//进行编译
				boolean isSucceed = compiler(file);
				if(!isSucceed)
					continue;
				//进行重载
				reload(file);
			
			} catch (Throwable e) {
				log.error("重载错误", e);
				e.printStackTrace();
			}
		}
	}
	
	
	/**
	 * 编译java文件
	 * @param fileList
	 * @throws Exception 
	 */
	private boolean compiler(File file) throws Exception
	{
		String absPath = file.getAbsolutePath()+File.separatorChar;
		List<String> fileList = FileUtil.listDirAllFiles(absPath);
		if (fileList == null || fileList.isEmpty())
			return false;
		
		for (String filepath : fileList) {
			if(!filepath.endsWith("java"))
				continue;
			String absFilePath = absPath+File.separatorChar+filepath;
			long time = FileUtil.getFileLastModifyTime(absFilePath);
			Long lastTime = fileMap.get(absFilePath);
			if (lastTime != null && lastTime.longValue() == time)
				continue;
			String className = filepath.substring(0, filepath.indexOf("."));
			// 截取包名
			String packageName = FileUtil.getClassPackage(absFilePath);

			// 获得java文件内容
			String content = FileUtil.readStringFileUTF8(absFilePath);

			// 进行编译
			boolean compilerSucceed = CompilerUtil.getInstance()
					.compilerJavaCode(packageName+"."+className, content);
			log.error("编译了文件"+filepath);
			if (!compilerSucceed)
			{
				continue;
			}
			log.error("编译成功了文件"+filepath);
			fileMap.put(absFilePath, time);
		}
		return true;
	}
	
	/**
	 * 重载
	 * @throws ClassNotFoundException 
	 * @throws IOException 
	 * @throws UnmodifiableClassException 
	 */
	private void reload(File file) throws ClassNotFoundException, IOException, UnmodifiableClassException
	{
		String absPath = file.getAbsolutePath()+File.separatorChar;
		List<String> fileList = FileUtil.listDirAllFiles(absPath);
		if (fileList == null || fileList.isEmpty())
			return;
		List<ClassDefinition> definitionList = new ArrayList<ClassDefinition>();
		Map<String, Long> changeMap = new HashMap<String, Long>();
		for(String filePath:fileList)
		{
			if(!filePath.endsWith(".class"))
				continue;
			long time = FileUtil.getFileLastModifyTime(absPath+File.separatorChar+filePath);
			Long lastTime = classMap.get(filePath);
			if (lastTime != null && lastTime.longValue() == time)
				continue;
			//判断是不是内部类
//			String filePathName = filePath.replace("$", ".");
			String filePathName = filePath;
			//去掉.class 和 \
			filePathName = filePathName.substring(0,filePathName.lastIndexOf("."));
			filePathName = filePathName.replaceAll("\\/", ".");
			filePathName = filePathName.replaceAll("\\\\", ".");
			
			Class cla = Class.forName(filePathName);
			byte[] bytes = FileUtil.loadClassData(absPath+File.separatorChar+filePath);
			ClassDefinition definition = new ClassDefinition(cla, bytes);
			definitionList.add(definition);
//			long now = System.currentTimeMillis();
//			FileUtil.writeFileLastModifyTime(absPath+File.separatorChar+filePath,now);
			changeMap.put(filePath, time);
			log.error("reload"+filePath);
		}
		
		//放在这里保证事务的一致性
		for(Map.Entry<String, Long> entry:changeMap.entrySet())
		{
			classMap.put(entry.getKey(), entry.getValue());
		}
		inst.redefineClasses(definitionList.toArray(new ClassDefinition[definitionList.size()]));
	} 
	
	
	
	public static void main(String[] args) {
//		new CheckThread(null).run();
		String filePath  ="cc.dd.class";
		System.out.println(filePath.substring(0,filePath.lastIndexOf(".")));
			
		
		
	}
	

}
